package com.nuoniu.sibanyun.service.erp.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nuoniu.sibanyun.common.exception.NuoNiuException;
import com.nuoniu.sibanyun.common.lang.StringUtils;
import com.nuoniu.sibanyun.entity.bo.UsedGradeRuleBo;
import com.nuoniu.sibanyun.entity.dto.ErpAccountingDto;
import com.nuoniu.sibanyun.entity.dto.ErpAccountingSearchDto;
import com.nuoniu.sibanyun.entity.erp.ErpAccounting;
import com.nuoniu.sibanyun.entity.vo.ErpAccountingVo;
import com.nuoniu.sibanyun.mapper.erp.ErpAccountingMapper;
import com.nuoniu.sibanyun.mapper.finance.VAccountingLedgerMapper;
import com.nuoniu.sibanyun.service.erp.IErpAccountService;
import com.nuoniu.sibanyun.service.erp.IErpAccountingService;
import com.nuoniu.sibanyun.service.erp.IErpGradeRuleService;
import com.nuoniu.sibanyun.service.finance.IVAccountingVoucherDetailService;
import com.nuoniu.sibanyun.userThread.UserInfo;
import com.nuoniu.sibanyun.userThread.UserThreadLocal;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 会计科目表 服务实现类
 * </p>
 *
 * @author baiqiang
 * @since 2020-09-25
 */
@Service
public class ErpAccountingServiceImpl extends ServiceImpl<ErpAccountingMapper, ErpAccounting> implements IErpAccountingService {

    @Autowired
    private IErpGradeRuleService erpGradeRuleService;
    @Autowired
    private IErpAccountService   accountService;
    @Autowired
    private IVAccountingVoucherDetailService accountingVoucherDetailService;
    @Autowired
    private VAccountingLedgerMapper ledgerMapper;

    @Override
    public Page<ErpAccountingVo> page(Page page, ErpAccountingSearchDto erpAccountingSearchDto) {
        UserInfo userInfo = UserThreadLocal.get();
        Integer currentAccountId = accountService.getCurrentAccountId();
        page = baseMapper.page(page, erpAccountingSearchDto, userInfo.getCompanyId(), currentAccountId);
        return page;
    }

    @Override
    public List<ErpAccountingVo> listErpAccountingByParentId(Integer parentId) {
        if( null == parentId )throw new NuoNiuException("父级ID不能为空");
        Integer currentAccountId = accountService.getCurrentAccountId();
        UserInfo userInfo = UserThreadLocal.get();
        List<ErpAccountingVo> erpAccountingVos = baseMapper.listErpAccountingByParentId(parentId,userInfo.getCompanyId(),currentAccountId);
        return erpAccountingVos;
    }

    public List<ErpAccountingVo> listDefErpAccounting(Integer industryId) {
        List<ErpAccountingVo> erpAccountingVos = baseMapper.listDefErpAccounting(industryId);
        return erpAccountingVos;
    }

    @Override
    public List<ErpAccountingVo> listFirstLevelErpAccountingByTypeId(Integer typeId) {
        UserInfo userInfo = UserThreadLocal.get();
        Integer currentAccountId = accountService.getCurrentAccountId();
        List<ErpAccountingVo> erpAccountingVos = baseMapper.listFirstLevelErpAccountingByTypeId(userInfo.getCompanyId(),currentAccountId,typeId);
        return erpAccountingVos;
    }

    @Override
    public List<ErpAccountingVo> listCurrentAll() {
        UserInfo userInfo = UserThreadLocal.get();
        Integer currentAccountId = accountService.getCurrentAccountId();
        List<ErpAccountingVo> erpAccountingVos = baseMapper.listCurrentAll(userInfo.getCompanyId(),currentAccountId);
        return erpAccountingVos;
    }

    @Override
    public void saveOrUpdateOne(ErpAccountingDto erpAccountingDto) {
        if(erpAccountingDto.getId() != null) {
            Integer vCount = accountingVoucherDetailService.getByAccountingId(erpAccountingDto.getId());
            if(vCount > 0) {
                throw new NuoNiuException("已在凭证中使用,不能修改");
            }
        }

        ErpAccounting erpAccounting = new ErpAccounting();
        Integer currentAccountId = accountService.getCurrentAccountId();
        LocalDateTime now = LocalDateTime.now();
        UserInfo userInfo = UserThreadLocal.get();
        Long id = erpAccountingDto.getId();
        ErpAccounting oldErpAccounting = getOneByCode(erpAccountingDto.getCode());
        if(null != oldErpAccounting && !(oldErpAccounting.getId().equals(id))) throw new NuoNiuException("保存失败，编码已经存在");
        ErpAccounting oneByName = getOneByName(erpAccountingDto.getName(), erpAccountingDto.getParentId(), erpAccountingDto.getAccountingTypeId());
        if(null != oneByName && !(oneByName.getId().equals(id))) throw new NuoNiuException("保存失败，当前级次的科目名称已经存在");
        String parentCode = "";
        Integer parentLevel = 0;
        Integer parentId = erpAccountingDto.getParentId();

        BeanUtils.copyProperties(erpAccountingDto, erpAccounting);
        if( null != parentId && parentId != 0){
            ErpAccounting parentErpAccounting = getById(parentId);
            if( null == parentErpAccounting) throw new NuoNiuException("找不到上级");
            if(id == null) {
                Integer vCount = accountingVoucherDetailService.getByAccountingId(parentId.longValue());
                if(vCount > 0) {
                    throw new NuoNiuException("已在凭证中使用,不能添加下级");
                }

                Integer lCount = ledgerMapper.getByAccountingId(parentId.longValue());
                if(lCount > 0) {
                    throw new NuoNiuException("已设置期初余额,不能添加下级");
                }
            }

            parentCode = parentErpAccounting.getCode();
            parentLevel = parentErpAccounting.getDepth();
            if(null == parentLevel) throw new NuoNiuException("父级级次错误");
            erpAccounting.setDepth(parentLevel + 1);
            erpAccounting.setTreeNames(parentErpAccounting.getTreeNames() + "/" + erpAccountingDto.getName());
            erpAccounting.setParentIds(parentErpAccounting.getParentIds() + "," + erpAccountingDto.getParentId());
            parentErpAccounting.setIsEndNode(false);
            updateById(parentErpAccounting);
        }else{
            erpAccounting.setTreeNames(erpAccounting.getName());
            erpAccounting.setDepth(1);
            erpAccounting.setParentIds("0");
            erpAccounting.setIsEndNode(true);
        }
        //校验 编码
        UsedGradeRuleBo usedGradeRuleBo = erpGradeRuleService.checkCode(erpAccountingDto.getCode(), parentCode, parentLevel, "code");

        erpAccounting.setGradeRuleLevel(usedGradeRuleBo.getGradeRuleLevel());
        erpAccounting.setGradeRuleStr(usedGradeRuleBo.getGradeRuleStr());

        if(null == id){
            erpAccounting.setCreatedTime(now);
            erpAccounting.setCompanyId(userInfo.getCompanyId());
            erpAccounting.setAccountId(currentAccountId);
            erpAccounting.setIsEndNode(true);
        }
        saveOrUpdate(erpAccounting);
    }


    @Override
    public ErpAccounting getOneByCode(String code) {
        if(StringUtils.isBlank(code)) throw new NuoNiuException("编码不能为空");
        UserInfo userInfo = UserThreadLocal.get();
        QueryWrapper<ErpAccounting> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("company_id",userInfo.getCompanyId());
        queryWrapper.eq("account_id", accountService.getCurrentAccountId());
        queryWrapper.eq("code",code);
        queryWrapper.last("LIMIT 1");
        ErpAccounting one = getOne(queryWrapper, false);
        return one;
    }

    @Override
    public ErpAccounting getOneByName(String name, Integer parentId, Integer typeId) {
        if(StringUtils.isBlank(name) )throw new NuoNiuException("科目名称不能为空");
        if(null == typeId)throw new NuoNiuException("科目分类不能为空");
        UserInfo userInfo = UserThreadLocal.get();
        QueryWrapper<ErpAccounting> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("company_id",userInfo.getCompanyId());
        queryWrapper.eq("name",name);
        queryWrapper.eq("account_id", accountService.getCurrentAccountId());
        queryWrapper.eq("accounting_type_id",typeId);
        if(null != parentId){
            queryWrapper.eq("parent_id",parentId);
        }
        queryWrapper.last("LIMIT 1");
        ErpAccounting one = getOne(queryWrapper, false);
        return one;
    }

    @Override
    public void batchDeleteByIds(Long id) {
        UserInfo userInfo = UserThreadLocal.get();
        //todo 查询 科目 是否 可以删除
        ErpAccounting accounting = getById(id);
        if(!userInfo.getCompanyId().equals(accounting.getCompanyId())) {
            throw new NuoNiuException("您没有此权限,先联系管理员");
        }

        Integer count = baseMapper.getByParentId(id);
        if(count > 0) {
            throw new NuoNiuException("有下级科目,不能删除");
        }

        Integer vCount = accountingVoucherDetailService.getByAccountingId(id);
        if(vCount > 0) {
            throw new NuoNiuException("已在凭证中使用,不能删除");
        }

        removeById(id);
        //判断父级是否末级
        if(accounting.getParentId() != null) {
            Integer pCount = baseMapper.getByParentId(accounting.getParentId().longValue());
            if(pCount == 0) {
                ErpAccounting erpAccounting = new ErpAccounting();
                erpAccounting.setId(accounting.getParentId().longValue());
                erpAccounting.setIsEndNode(true);
                updateById(erpAccounting);
            }
        }
    }

    @Override
    public ErpAccounting getOneByCondition(Integer actionType, Long currentId) {
        UserInfo userInfo = UserThreadLocal.get();
        Integer currentAccountId = accountService.getCurrentAccountId();
        ErpAccounting result = null;
        switch (actionType){
            case 1: result = baseMapper.getPreId(userInfo.getCompanyId(), currentAccountId, currentId); break;
            case 2: result = baseMapper.getNextId(userInfo.getCompanyId(), currentAccountId, currentId); break;
            case 3: result = baseMapper.getFirstId(userInfo.getCompanyId(), currentAccountId); break;
            case 4: result = baseMapper.getLastId(userInfo.getCompanyId(), currentAccountId); break;
        }
        return result;
    }

    @Async
    public void initData(UserInfo userInfo, Integer accountId) {
        baseMapper.initData(userInfo.getCompanyId(), accountId);
    }

    @Override
    public Integer getByCurrency(Long id) {
        return baseMapper.getByCurrency(id);
    }

    @Override
    public List<ErpAccounting> getByParentIds(String parentIds) {
        return baseMapper.getByParentIds(parentIds);
    }

//    @Override
//    public void updateDescription() {
//        String jsonStr = baseMapper.getJson();
//        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
//        jsonObject.entrySet().forEach(f->{
//            String key = f.getKey();
//            Object value = f.getValue();
//            String valStr = value.toString();
//            baseMapper.updateAccinformation(valStr,key);
//        });
//    }


}
